/*
 * StreamEnd.cpp
 *
 *  Created on: 2011-3-29
 *      Author: hao
 */

#include "StreamEnd.h"
#include <unistd.h>
#include <dlfcn.h>

StreamEnd::StreamEnd(const char * szPath) : patch(szPath), CreateStream_function(NULL), DestroyStream_function(NULL),
StreamStop_function(NULL), StreamStart_function(NULL),
StreamPause_function(NULL), SetVolumeDB_function(NULL),
SetVolumeLinear_function(NULL), SetChannleVolumeDB_function(NULL),
SetChannleVolumeLinear_function(NULL), SteamGetCurrentTime(NULL) {
    // TODO Auto-generated constructor stub
    streamEndHandle = NULL;

}

bool StreamEnd::Init() {

    if (streamEndHandle)
        return false;

    if (access(patch.c_str(), F_OK) == -1) {

        return false;

    }

    streamEndHandle = dlopen(patch.c_str(), RTLD_LAZY);

    if (!streamEndHandle)
        return false;

    init_function = (bool(*)()) dlsym(streamEndHandle, "StreamEndInit");

    destroy_function = (bool(*)()) dlsym(streamEndHandle, "StreamEndDestroy");

    CreateStream_function = (bool(*)(int, int, int)) dlsym(streamEndHandle,
            "CreateStream");

    DestroyStream_function
            = (bool(*)()) dlsym(streamEndHandle, "DestroyStream");

    StreamStop_function = (void(*)()) dlsym(streamEndHandle, "StreamStop");

    StreamStart_function = (void(*)()) dlsym(streamEndHandle, "StreamStart");

    StreamPause_function = (void(*)()) dlsym(streamEndHandle, "StreamPause");

    setWriteCallback_function = (void(*)(const std::function<bool(void*,
            size_t, size_t*)>&)) dlsym(streamEndHandle,
            "SetWriteStreamCallback");

    setDrainCallback_function = (void(*)(const std::function<void()>&)) dlsym(
            streamEndHandle, "SetDrainStreamCallback");

    if (!init_function || !destroy_function || !CreateStream_function
            || !DestroyStream_function || !StreamStop_function
            || !StreamStart_function || !StreamPause_function
            || !setWriteCallback_function || !setDrainCallback_function) {
        dlclose(streamEndHandle);
        init_function = NULL;
        destroy_function = NULL;

        CreateStream_function = NULL;
        DestroyStream_function = NULL;

        StreamStop_function = NULL;

        StreamStart_function = NULL;

        StreamPause_function = NULL;

        setWriteCallback_function = NULL;

        setDrainCallback_function = NULL;

        return false;
    }

    SetVolumeDB_function = (void(*)(double)) dlsym(streamEndHandle,
            "SetVolumeDB");

    SetVolumeLinear_function = (void(*)(double)) dlsym(streamEndHandle,
            "SetVolumeLinear");

    SetChannleVolumeDB_function = (void(*)(int, double)) dlsym(streamEndHandle,
            "SetChannleVolumeDB_function");

    SetChannleVolumeLinear_function = (void(*)(int, double)) dlsym(
            streamEndHandle, "ChannleSetVolumeLinear");

    SteamGetCurrentTime = (unsigned long long(*)())dlsym(streamEndHandle, "StreamGetCurTime");

    return init_function();

}

bool StreamEnd::CreateStream(
        const std::function<bool(void *, size_t, size_t *)> & write_callback,
        const std::function<void()> & drain_callback, int sample_format,
        int channels, int rate) {

    setWriteCallback_function(write_callback);

    setDrainCallback_function(drain_callback);

    return CreateStream_function(sample_format, channels, rate);

}

bool StreamEnd::DestroyStream() {
    return DestroyStream_function();
}

void StreamEnd::StreamStop() {

    StreamStop_function();

}

void StreamEnd::StreamStart() {

    StreamStart_function();

}

void StreamEnd::StreamPause() {

    StreamPause_function();

}

void StreamEnd::SetVolumeDB(double db) {
    if (SetVolumeDB_function)
        SetVolumeDB_function(db);
}

void StreamEnd::SetVolumeLinear(double linear) {
    if (SetVolumeLinear_function)
        SetVolumeLinear_function(linear);
}

void StreamEnd::ChannleSetVolumeDB(int channle, double db) {
    if (SetChannleVolumeDB_function)
        SetChannleVolumeDB_function(channle, db);
}

void StreamEnd::ChannleSetVolumeLinear(int channle, double linear) {
    if (SetChannleVolumeLinear_function)
        SetChannleVolumeLinear_function(channle, linear);
}

unsigned long long StreamEnd::getStreamCurrentTime() {
    if (SteamGetCurrentTime)
        return SteamGetCurrentTime();
    return 0;
}

StreamEnd::~StreamEnd() {
    // TODO Auto-generated destructor stub

    if (!DestroyStream_function) return;

    DestroyStream_function();

    destroy_function();

    init_function = NULL;
    destroy_function = NULL;

    CreateStream_function = NULL;
    DestroyStream_function = NULL;

    StreamStop_function = NULL;

    StreamStart_function = NULL;

    StreamPause_function = NULL;

    setWriteCallback_function = NULL;

    setDrainCallback_function = NULL;

    if (streamEndHandle) {
        dlclose(streamEndHandle);
        streamEndHandle = NULL;
    }


}
